package com.travel.WeChatPay;


import com.google.gson.Gson;

import com.travel.config.PayInfoConfig;
import com.travel.utils.BaseContext;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.wechat.pay.java.core.http.Constant.*;

/**
 *
 * @author Rick chou
 * @date 2024/7/16 9:10
 * 微信支付BO
 *
 */
@Slf4j
@Component
public class WechatPayBo {



    private static PayInfoConfig payInfoConfig;  // 仍然是静态的，但不使用 @Resource 直接注入

    @Autowired
    public WechatPayBo(PayInfoConfig payInfoConfig) {
        WechatPayBo.payInfoConfig = payInfoConfig; // **手动赋值给静态变量**
    }
    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:16
     * 支付回调
     *
     */
    public static Transaction payNotify(HttpServletRequest request) throws Exception {
        NotificationConfig config = buildNotifyConfig();
        NotificationParser parser = new NotificationParser(config);
        RequestParam requestParam = parseNotify(request);
        Transaction parse = null;
        try {
            parse = parser.parse(requestParam, Transaction.class);
        }catch (ValidationException e){
            log.error("sign verification failed", e);
        }
        return parse;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:33
     * 解析回调结果
     *
     */
    private static RequestParam parseNotify(HttpServletRequest request)throws IOException {
        // 读取请求体
        String data = getRequestBody(request);
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        String signType = request.getHeader("Wechatpay-Signature-Type");
        String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);

        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(signType)         // 若未设置signType，默认值为 WECHATPAY2-SHA256-RSA2048
                .body(data)
                .build();
        return requestParam;
    }
    /**
     * 获取请求体内容
     */
    private static String getRequestBody(HttpServletRequest request) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
        }
        return stringBuilder.toString();
    }
    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:35
     * 构建支付请求SERVICE
     *
     */
    public static JsapiService getService() throws IOException {

        Config config = payInfoConfig.rsaAutoCertificateConfig();

        JsapiService service = new JsapiService.Builder().config(config).build();
        return service;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:31
     * 构造NOTIFY_CONFIG
     *
     */
    private static NotificationConfig buildNotifyConfig(){
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(payInfoConfig.getMchId())
                .privateKeyFromPath(payInfoConfig.getKeyPemPath())
                .merchantSerialNumber(payInfoConfig.getMchSerialNo())
                .apiV3Key(payInfoConfig.getApiV3Key())
                .build();
        return config;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:35
     * 构建支付请求参数
     *
     */
    private static PrepayRequest buildParam(BigDecimal price, String orderId, Long userId,String payType){
        PrepayRequest prepayRequest = new PrepayRequest();  // 构建PrepayRequest对象
        Amount amount = new Amount();
        // 使用 BigDecimal 的 multiply 方法来进行乘法操作
        amount.setTotal(price.multiply(new BigDecimal(100)).intValue());  // 乘以 100 后转为整数
        prepayRequest.setAmount(amount);
        prepayRequest.setAppid(payInfoConfig.getAppId());
        prepayRequest.setMchid(payInfoConfig.getMchId());
        prepayRequest.setNotifyUrl(payInfoConfig.getNotifyUrl());				// 回调接口地址
        prepayRequest.setDescription("微信支付");
        prepayRequest.setOutTradeNo(orderId);       // 订单号
        // 创建一个Map或者对象来存储 orderId 和 payType
        Map<String, String> attachMap = new HashMap<>();
        attachMap.put("userId", BaseContext.getCurrentId() + "");
        attachMap.put("payType", payType);

        // 使用 Gson 将 Map 转换为 JSON 字符串
        String attachJson = new Gson().toJson(attachMap);

        // 将 JSON 字符串赋值给 Attach
        prepayRequest.setAttach(attachJson);                                  // 订单类型(回调时可根据这个数据辨别订单类型或其他)
        //根据token拿到openid,指定该预支付订单的支付者身份
        Payer payer = new Payer();
        payer.setOpenid(BaseContext.getOpenId(userId));
        prepayRequest.setPayer(payer);
        return prepayRequest;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:53
     * 解析支付结果
     *
     */
    private static Map<String,Object> parsePay(PrepayResponse response) throws Exception {
        Map<String, Object> params = new HashMap<>();
        Long timeStamp = System.currentTimeMillis() / 1000;
        String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        String signatureStr = Stream.of(
                payInfoConfig.getAppId(),
                String.valueOf(timeStamp),
                substring,
                "prepay_id=" + response.getPrepayId()
        ).collect(Collectors.joining("\n", "", "\n"));
        String sign = WXPayUtil.getSign(signatureStr,payInfoConfig.getKeyPemPath());
        params.put("paySign", sign);
        params.put("timeStamp", String.valueOf(timeStamp));
        params.put("nonceStr", substring);
        params.put("signType", "RSA");
        params.put("package", "prepay_id=" + response.getPrepayId());
        return params;
    }


    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:47
     * 调起支付
     *
     */
    public static Map<String, Object> payment(BigDecimal price, String orderId, Long userId,String payType) throws Exception {
        JsapiService service = getService();
        PrepayRequest prepayRequest = buildParam(price, orderId, userId, payType);
        PrepayResponse response = service.prepay(prepayRequest); // 调用 JsapiService的 prepay 方法拿到预支付对象
        Map<String, Object> result = parsePay(response);  // 解析预支付对象
        result.put("orderId",orderId);
        return result;
    }




}
